package org.kgduyjj.toolkit.builder;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

/**
 * 参考{@link Optional}编写一个Bean对象构造器
 * 
 * @author Kgduyjj
 *
 * @param <T>
 */
public class BeanBuilder<T> {
    /** 被处理的值 */
    private final T value;

    /** 空值的对象 */
    private static final BeanBuilder<?> EMPTY = new BeanBuilder<>();

    /**
     * 构造 空值
     */
    private BeanBuilder() {
        this.value = null;
    }

    /**
     * 构造
     * 
     * @param value
     */
    private BeanBuilder(final T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 构建一个空值操作对象
     * 
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    private final static <T> BeanBuilder<T> empty() {
        return (BeanBuilder<T>) EMPTY;
    }

    /**
     * 直接传入操作值对象
     * 
     * @param <T>
     * @param bean
     * @return
     */
    public static <T> BeanBuilder<T> ofNullable(T bean) {
        return Objects.isNull(bean) ? empty() : new BeanBuilder<>(bean);
    }

    /**
     * 通过供给函数 {@code Supplier} 构建操作值对象，且会对空参数进行容错处理
     * 
     * @param <T>
     * @param beanSupplier
     * @return
     */
    public static <T> BeanBuilder<T> ofNullable(Supplier<T> supplier) {
        return Objects.isNull(supplier) ? empty() : ofNullable(supplier.get());
    }

    /**
     * 值是否不为空
     * 
     * @return
     */
    public boolean isPresent() {
        return value != null;
    }

    /**
     * 返回该值
     * 
     * @return
     */
    public T get() {
        return value;
    }

    /**
     * 返回该值，若不存在则返回其他值
     * 
     * @param other
     * @return
     */
    public T orElse(T other) {
        return isPresent() ? value : other;
    }

    /**
     * 返回该值，若不存在则通过消费者接口提供
     * 
     * @param other
     * @return
     */
    public T orElseGet(Supplier<? extends T> supplier) {
        Objects.requireNonNull(supplier);
        return isPresent() ? value : supplier.get();
    }

    /**
     * 为被包裹的值设置属性内容，可以被串联
     * 
     * @param <P>
     * @param added
     * @param biConsumer
     * @param property
     * @return
     */
    public <P> BeanBuilder<T> join(boolean added, BiConsumer<T, P> biConsumer, P property) {
        Objects.requireNonNull(biConsumer);
        if (added && isPresent()) {
            biConsumer.accept(value, property);
        }
        return this;
    }

    /**
     * 为被包裹的值设置属性内容，可以被串联
     * 
     * @param <P>
     * @param biConsumer
     * @param property
     * @return
     */
    public <P> BeanBuilder<T> join(BiConsumer<T, P> biConsumer, P property) {
        return join(true, biConsumer, property);
    }

    /**
     * 把值转化为Map对象
     * 
     * @return
     */
    public Map<String, Object> toMap() {
        Objects.requireNonNull(value);
        Map<String, Object> map = new HashMap<String, Object>();
        Field[] fields = value.getClass().getDeclaredFields(); // 获取f对象对应类中的所有属性域
        for (int i = 0, len = fields.length; i < len; i++) {
            String fieldName = fields[i].getName();
            fieldName = fieldName.toLowerCase(); // 将key置为小写，默认为对象的属性
            try {
                boolean accessFlag = fields[i].isAccessible(); // 获取原来的访问控制权限
                fields[i].setAccessible(true); // 修改访问控制权限
                Object o = fields[i].get(value); // 获取在对象f中属性fields[i]对应的对象中的变量
                if (o != null) {
                    map.put(fieldName, o.toString());
                }
                fields[i].setAccessible(accessFlag); // 恢复访问控制权限
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            } catch (IllegalAccessException ex) {
                ex.printStackTrace();
            }
        }
        return map;
    }
}
